﻿<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width">
    <link rel="icon" href="title.jpg" sizes="16x16">
    <title>画布</title>
    <style>
        *{
            margin: 0;
            padding: 0;
        }
        @keyframes upload {
        0% {
            opacity: 0;
        }

        50% {
            opacity: .4;
        }

        100% {
            opacity: .6;
        }
    }
        .d11{
            display: none;
            justify-content: center;
            align-items: center;
            margin-bottom: 3px;
            flex-wrap: wrap;
        }
        .huaban{
            position: absolute;
            width: 100%;
            height: 100%;
        }
        button{
             font-size: larger;
             margin: 0 1px;
        }
        .d11 button{
            flex: auto;
        }
        .btn{
            flex:1;
        }
        h4{
            margin: 2px;
        }
    </style>
</head>

<body onload="init()" style="background-color:rgb(119, 237, 204, 1.0);">
    <div id="d0" style="position: relative;background: pink;margin: 0 auto;">
        <div id="canvas3" style="position: relative;background: white;">
            <canvas class="huaban"></canvas>
            <canvas class="huaban"></canvas>
            <canvas class="huaban"></canvas>
        </div>
        <div id='d1' style="position: absolute;bottom: 0;width: 100%;">
            <div style="width:100%;">
                <div class="d11">
                    <input oninput="getPenSize(event)" type="range" min="1" max="20" step="1" value="2" style="flex:auto;" />
                </div>
                <div class="d11">
                    <input class="oh1" oninput="getTextHeight(event)" type="range" value="5" min="1" max="10" step="1" style="width: 100vw;display: none;" />
                    <div id="oh11" style="width: 100%;margin-top: 5px;display: flex;justify-content: space-evenly;">
                        <button style="flex:1" class="oh" data-index='0'>H</button>
                        <button style="flex:1" id="textDirection" onclick="setTextDirection()">竖</button>
                    </div>
                </div>
                <div class="d11">
                    <input oninput="getEraserSize(event)" type="range" min="10" max="100" step="1" value="80" style="flex:auto;" />
                    <input oninput="getEraserType(event)" type="radio" name="teraser" checked="true" value="0" />方
                    <input oninput="getEraserType(event)" type="radio" name="teraser" value="1" />圆
                </div>
                <div class="d11">
                    <button class="obtn" style="display:none;" onclick="nimgOpacity()">-</button>
                    <button class="obtn" style="display: none;" onclick="pimgOpacity()">+</button>
                    <button onclick="hide()">收起</button>
                    <button style="flex: 1;" id="btn_undo" disabled="true" onclick="undo()">撤销</button>
                </div>
            </div>
            <div style="display: flex;align-items: stretch;width: 100%;overflow-x: auto;">
                <button class="btn" data-index='0'>画笔</button>
                <button class="btn" data-index='1' style="color:red;">牙文</button>
                <button class="btn" data-index='2'>橡皮</button>
                <input class="btn" style="flex: 1;margin: 0 1px;box-sizing: content-box;" type="color" oninput="getColor(event)" />
                <button id="btn_upload" style="flex: 1;display: none;" onclick="uploadPng()">发送</button>
                <button class="btn" style="flex: 1;" data-index='3'>···</button>
            </div>
        </div>
        <div id="helpMsg" style="position:absolute;height: 90%;top: 0;overflow: scroll;background-color: whitesmoke;width: 100%;display: none;">
            <h4>牙文即涂鸦文</h4>
            <h4>输入方式：</h4>
            <h4>第一步：输入文字</h4>
            <h4>第二步：点击画布空白区域或确定按钮</h4>
            <h4>长按并移动选择输入位置</h4>
            <img src="images/help.jpg" style="width:100%" />
            <div style="position: absolute;bottom: 0;width: 100%;display: flex;justify-content: center;align-items: center;">
                <button style="font-size: large;" id="closeBtn" onclick="stopHide()">5秒后关闭</button>
                <button style="font-size:large;" onclick="hideHelp()">立即关闭</button>
            </div>
        </div>
        <button id='b2' style="width: 100%;position: absolute;bottom: 0px;display:none;opacity: 0.1;animation: upload 2s reverse;">弹出</button>
        <div id="d3" style="display:none;position: absolute;bottom: 0;width: 100%;opacity: .9;">
        <button style="flex:1" onclick="tcancel()">取消</button>
        <button style="flex:1" onclick="textundo()">后退</button>
        <button style="flex:1" onclick="tconfirm()">确定</button>
    </div>
    </div>
    <div id="msg" style="display: none;justify-content: center;align-items: center;position:fixed;top: 30px;width: 100%;">
        <div style="position:relative;padding: 4px 8px;background-color: greenyellow;border-radius: 6px;">
            <span id="msgtxt" style="position: relative;font-size: 18px;"></span>
            <div style="background-color: white;position: absolute;top: 0;left: 0;width: 100%;height:100%;animation: upload 2s alternate infinite;">
            </div>
        </div>
    </div>
    <div id="vfxMask" onclick="vfxEnd()" style="position:fixed;top: 0;left: 0;width: 100%;height: 100%;display: none;">
    </div>
    <script type="text/javascript">
    window.ontouchstart = function(event) {
        event.preventDefault()
    }
    var msg = document.getElementById('msg')
    var msgtxt = document.getElementById('msgtxt')
    var msgTimer
    var vfxMask = document.getElementById('vfxMask')
    var helpMsg = document.getElementById('helpMsg')
    var closeBtn = document.getElementById('closeBtn')

    function hideHelp() {
        helpMsg.style.display = 'none'
    }

    function stopHide() {
        clearInterval(timeId)
        //closeBtn.style.display = 'none'
    }
    var ohBtn = document.getElementsByClassName('oh')
    //文字透明度和高度按钮
    var obtn = document.getElementsByClassName('obtn')
    for (var i = 0; i < ohBtn.length; i++) {
        ohBtn[i].addEventListener('click', ohHandle)
    }

    function ohHandle(evt) {
        var index = Number(evt.target.dataset.index)
        var display = getComputedStyle(oh1[index])['display']
        for (var i = 0; i < oh1.length; i++) {
            if (i == index) {
                oh1[i].style.display = display == 'flex' ? 'none' : 'flex'
            } else {
                oh1[i].style.display = 'none'
            }
        }
    }
    var textDirectionBtn = document.getElementById('textDirection')
    var oh1 = document.getElementsByClassName('oh1')
    var oh11 = document.getElementById('oh11')
    //透明度按钮
    var varr = [0, 0.2, 0.4, 0.6, 0.8, 1]
    varr.forEach(value => {
        var btn = document.createElement('button')
        btn.innerText = value
        btn.dataset.index = value
        btn.style.flex = 1
        btn.addEventListener('click', setOpacity)
        oh11.append(btn)
    })
    var opacityIndex = 1
    //当前选中透明度按钮
    function setOpacity(evt) {
        //console.log("index:", evt.target.dataset.index)
        var index = Number(evt.target.dataset.index)
        if (opacityIndex != index) {
            //console.log("opacityIndex:", opacityIndex)
            var length = hbimagedata.length
            DataURLtoCanvas(hbimagedata[length - 1], index)
            opacityIndex = index
        }
    }

    function DataURLtoCanvas(path, alpha) {
        var img = new Image()
        img.onload = () => {
            myCtx[0].save()
            myCtx[0].globalAlpha = alpha
            clearCanvas(myCtx[0], myCanvas[0])
            myCtx[0].drawImage(img, 0, 0, myCanvas[0].width / dpr, myCanvas[0].height / dpr)
            myCtx[0].restore()
        }
        img.src = path
    }

    var btn_undo = document.getElementById('btn_undo')
    //撤销按钮
    var hbimagedata = []
    var uploadData
    var mTimer
    var msgTimer
    var hbMode = 1
    var dpr = window.devicePixelRatio
    var isMouseDown = false
    var isMove = false
    var startX, startY
    var myRect
    var tid = false
    var phpquery = 'saveImg.php'
    var pngname
    var huabuType
    var nickname
    var canvasWidth
    var canvasHeight
    var text_Direction = 0
    var scaleW = 9
    var scaleH = 16
    var text = {
        x: 0,
        y: 0,
        path2d: [],
        textimagedata: [],
        margin: {
            top: 3,
            bottom: 3,
            left: 3,
            right: 3
        },
        step: 1, //文字框移动步长
        scale: 1,
        rotate: 1,
        textheight: 0,
        fontsize: 2,
        drawsize: 2,
        width: 45,
        height: 0,
        point: { min: { x: null, y: null }, max: { x: null, y: null } }
    }
    var eraser = {
        type: 0,
        size: 80,
        x: 150,
        y: 150
    }
    var startTimeStamp
    var isLongTap = false
    var lTimer
    var isUploading = false
    var imgOpa

    function undo() {
        var L = hbimagedata.length
        //console.log('L:', L)
        if (L > 1) {
            hbimagedata.pop()
            DataURLtoCanvas(hbimagedata[L - 2], 1)
            //console.log("length:", hbimagedata.length)
            if (hbimagedata.length < 2) {
                btn_undo.disabled = true
            }
        }
    }

    function setTextDirection() {
        text_Direction = text_Direction ? 0 : 1
        textDirectionBtn.innerText = text_Direction ? '竖' : '横'
        switch (text_Direction) {
            case 0:
                text.width = 0
                text.height = scaleH * 3
                text.x = 0
                text.y = 0
                break;
            case 1:
                text.width = scaleW * 5
                text.height = 0
                text.x = canvasWidth
                text.y = 0
                break;
        }
        initText(false)
        drawTextBox()
    }

    function isCanvasBlank(canvas) {
        var blank = document.createElement('canvas');
        blank.width = canvas.width;
        blank.height = canvas.height;
        return canvas.toDataURL() == blank.toDataURL();
    }

    function isdiff(arr1, arr2) {
        var L1 = arr1.length
        var L2 = arr2.length
        if (L1 != L2) {
            return true
        } else {
            for (var i = 0; i < L1; i++) {
                if (arr1[i] != arr2[i]) {
                    //console.log('arr1,arr2,i:', arr1[i], arr2[i], i)
                    return true
                }
            }
        }
        return false
    }

    function pushimagedata(flag) {
        var imagedata = myCanvas[0].toDataURL()
        if (flag) {
            var L = hbimagedata.length
            var tdata = hbimagedata[L - 1] || ''
            if (imagedata != tdata) {
                hbimagedata.push(imagedata)
                //console.log('push length:', hbimagedata.length)
            }
        } else {
            hbimagedata.push(imagedata)
        }
        if (hbimagedata.length > 1) {
            if (btn_undo.disabled) {
                btn_undo.disabled = false
            }
        } else {
            btn_undo.disabled = true
        }
        //console.log("hbimagedata:tt", hbimagedata)
    }

    function getPenSize(event) {
        var size = Number(event.target.value)
        myCtx[0].lineWidth = text.fontsize = size
        clearCanvas(myCtx[2], myCanvas[2])
        myCtx[2].fillRect(0, 100, 1000, size)
        setTimeout(() => {
            clearCanvas(myCtx[2], myCanvas[2])
        }, 1000)
    }

    function getTextHeight(event) {
        switch (text_Direction) {
            case 0:
                text.height = Number(event.target.value) * scaleH
                break;
            case 1:
                text.width = Number(event.target.value) * scaleW
                break;
        }
        scale_width_height()
        setRemainderWidth()
        drawTextBox()
    }

    function getTextY() {
        var y = text.y + getHeightMargin()
        if (text.remainderwidth > 0) {

        }
    }

    function getHeightMargin() {
        return text.height + text.margin.top + text.margin.bottom
    }

    //msg
    function showMsg(txt, flag) {
        msg.style.display = 'flex'
        msgtxt.innerText = txt
        clearTimeout(msgTimer)
        if (flag) {
            msgTimer = setTimeout(() => {
                msg.style.display = 'none'
            }, 2000)
        }
    }

    function setTextX() {
        var imagedata = myCtx[0].getImageData(0, 0, myCanvas[0].width, myCanvas[0].height)
        var x = myCanvas[0].width - getWidthMargin() * dpr / 2
        //console.log("imagedata:", imagedata, myCanvas[0].width)
        for (var j = myCanvas[0].width - getWidthMargin() * dpr / 2; j > getWidthMargin() * dpr; j -= getWidthMargin() * dpr) {
            //console.log("j:", j)
            for (var k = 0; k < imagedata.height; k++) {
                //console.log("K:", k, imagedata.data[k * (imagedata.width * 4) + j * 4 + 3])
                if (imagedata.data[k * (imagedata.width * 4) + Math.round(j) * 4 + 3] > 60) {
                    //console.log("pixel:", imagedata.data[k * (imagedata.width * 4) + j * 4 + 3])
                    break
                }
                if (k == (imagedata.height - 1)) {
                    x = j
                    //console.log("height:k:", imagedata.height, k)
                }
            }
            if (x != myCanvas[0].width - getWidthMargin() * dpr / 2) {
                break
            }
        }
        //console.log("setTextX-x:", x, x > getWidthMargin() ? x / dpr + text.width / 2 + text.margin.right : x / dpr)
        return x > getWidthMargin() ? x / dpr + getWidthMargin() / 2 : getWidthMargin()
    }

    function setTextY() {
        var imagedata = myCtx[0].getImageData(0, 0, myCanvas[0].width, myCanvas[0].height)
        var y = 0
        //console.log("imagedata:", imagedata)
        for (var j = (text.margin.top + text.height / 2) * dpr; j < imagedata.height; j += getHeightMargin() * dpr) {
            //console.log("j:", j)
            for (var k = 0; k < imagedata.width; k++) {
                if (imagedata.data[Math.round(j) * (imagedata.width * 4) + k * 4 + 3] > 60) {
                    //console.log("pixel:", imagedata.data[j * (imagedata.width * 4) + k * 4 + 3])
                    break
                }
                if (k == imagedata.width - 1) {
                    y = j
                    //console.log("width:k:", imagedata.width, k)
                }
            }
            if (y != 0) {
                break
            }
        }
        return y > 0 ? y / dpr - text.height / 2 - text.margin.top : y / dpr
    }

    function getEraserSize(event) {
        eraser.size = Number(event.target.value)
        erase(eraser.x, eraser.y, false)
    }

    function getEraserType(event) {
        //console.log(event)
        eraser.type = Number(event.target.value)
        erase(eraser.x, eraser.y, false)
    }
    var b2 = document.getElementById('b2')
    var d1 = document.getElementById('d1')
    var d11 = document.getElementsByClassName('d11')
    var d3 = document.getElementById('d3')
    b2.addEventListener('click', show)
    var btn = document.getElementsByClassName('btn')
    //console.log(btn)
    for (var i = 0; i < btn.length; i++) {
        btn[i].addEventListener('click', clickBtn)
        // btn[i].addEventListener('touchstart', clickBtn)
    }


    function getColor(event) {
        //console.log(event)
        myCtx[0].strokeStyle = event.target.value
    }

    function hide() {
        d1.style.display = 'none'
        b2.style.display = 'block'
        //onclick="hide()"
    }

    function clickBtn(evt) {
        // evt.preventDefault()
        //console.log(evt, evt.target.dataset.index)
        var index = Number(evt.target.dataset.index)
        //点击0画笔/1文字/2橡皮擦/
        for (var i = 0; i < 4; i++) {
            if (i == index) {
                var display = getComputedStyle(d11[index])['display']
                display = display == 'none' ? 'flex' : 'none'
                d11[index].style.display = display
                if (index < 3) {
                    if (hbMode != index) {
                        switch (index) {
                            case 0:
                                clearCanvas(myCtx[1], myCanvas[1])
                                if (hbMode == 1) {
                                    initText(true)
                                }
                                break
                            case 1:
                                drawTextBox()
                                break;
                            case 2:
                                if (hbMode == 1) {
                                    initText(true)
                                }
                                erase(150, 150, false)
                                break
                        }
                        hbMode = index
                    }
                    btn[index].style.color = 'red'
                }
            } else {
                d11[i].style.display = 'none'
                if (index < 3)
                    btn[i].style.color = 'black'
            }
        }
    }

    function show(evt) {
        // evt.preventDefault()
        d1.style.display = 'block'
        b2.style.display = 'none'
    }

    var myCanvas = document.getElementsByTagName('canvas')
    var d0 = document.getElementById('d0')
    var canvas3 = document.getElementById("canvas3")
    var myCtx = []
    for (var i = 0; i < myCanvas.length; i++) {
        myCtx.push(myCanvas[i].getContext('2d', { willReadFrequently: true }))
    }


    myCanvas[2].addEventListener('mousedown', start)
    myCanvas[2].addEventListener('mousemove', move)
    myCanvas[2].addEventListener('mouseup', end)
    // myCanvas[2].addEventListener('mouseout', end)
    myCanvas[2].addEventListener('touchstart', start)
    myCanvas[2].addEventListener('touchmove', move)
    myCanvas[2].addEventListener('touchend', end)


    function tcancel() {
        initText(true)
        drawTextBox()
    }

    function textundo() {
        var L = text.textimagedata.length
        if (L > 1) {
            text.textimagedata.pop()
            text.path2d.pop()
            myCtx[2].putImageData(text.textimagedata[L - 2], 0, 0)
            if (set_point()) {
                scale_width_height()
                setRemainderWidth()
                clearCanvas(myCtx[1], myCanvas[1])
                drawTextBox()
            }
        } else if (L > 0) {
            initText(true)
            drawTextBox()
        }
    }

    function set_point() {
        var pArr = text.path2d
        var min = { x: pArr[0][0].x, y: pArr[0][0].y }
        var max = { x: pArr[0][0].x, y: pArr[0][0].y }
        pArr.forEach(arr => {
            arr.forEach(point => {
                if (point.x < min.x) {
                    min.x = point.x
                }
                if (point.y < min.y) {
                    min.y = point.y
                }
                if (point.x > max.x) {
                    max.x = point.x
                }
                if (point.y > max.y) {
                    max.y = point.y
                }
            })
        })
        var tmin = text.point.min
        var tmax = text.point.max
        if (min.x == tmin.x && min.y == tmin.y && max.x == tmax.x && max.y == tmax.y) {
            return false
        } else {
            text.point = { min, max }
            return true
        }
    }

    function tconfirm() {
        confirmText()
    }

    var btn_upload = document.getElementById('btn_upload')
    var folder = 'others'

    var closeTime = 4
    var timeId

    function init() {
        /*
        timeId = setInterval(() => {
            if (closeTime < 0) {
                hideHelp()
                clearInterval(timeId)
            } else {
                closeBtn.innerText = closeTime + "秒后关闭"
                closeTime--
            }
        }, 1000)
        */
        var query = location.search
        var params = new URLSearchParams(query)
        tid = pngname = params.get('f')
        huabuType = params.get('t')
        nickname = params.get('n')
        phpquery += '?tid=' + tid + '&type=' + huabuType
        //console.log("pngname:", pngname)
        //console.log("huabuType:", huabuType)
        var p1 = /^[a-zA-Z0-9]+$/
        if (pngname && p1.test(pngname)) {
            switch (huabuType) {
                case '1':
                    //好友列表测试保存文件更新数据库
                    //数据表
                    //folder = "friendtest"
                    folder="chatPng";
                    break;
                case '2':
                    //保存文件且更新数据库
                    folder = "channel"

                    var hbstr = localStorage.getItem("hblist")
                    var hblist = JSON.parse(hbstr || "[]")
                    if (!hblist.includes(pngname)) {
                        hblist.push(pngname)
                        localStorage.setItem("hblist", JSON.stringify(hblist))
                    }
                    break;
                case '3':
                    folder = "geolocation"
                    break;
                case '4':
                    //点击评论画布
                    pngname = 'c' + tid
                    folder = "treehole"
                    setBlock()
                    setComment('g' + tid)
                    break;
                case '5':
                    folder = "friend"
                    break;
                case '6':
                    //点击主画布
                    pngname = 'g' + tid
                    folder = "treehole"
                    setBlock()
                    setGraffiti('c' + tid)
                    break;
                default:
                    pngname = ""
            }
            /*
            var p2 = /^[gc]\d{0,13}$/
            var p3 = /^[ew]\d+[ns]\d+$/
            if (p2.test(pngname) || p3.test(pngname)) {
                if (p2.test(pngname)) {
                    folder = 'treehole'
                } else if (p3.test(pngname)) {
                    folder = 'geolocation'
                }
            } else {
                var hbstr = localStorage.getItem("hblist")
                var hblist = JSON.parse(hbstr || "[]")
                if (!hblist.includes(pngname)) {
                    hblist.push(pngname)
                    localStorage.setItem("hblist", JSON.stringify(hblist))
                }
            }*/
        } else {
            pngname = ''
        }
        initHB()
        myRect = myCanvas[2].getBoundingClientRect()
        //console.log('pngname:', pngname)
        if (pngname) {
            if (nickname) {
                setTitle('与' + nickname + '聊天中')
            } else {
                setTitle(pngname)
            }
            pathToCanvas(folder + '/' + pngname + '.png')
            btn_upload.style.display = 'block'
        } else {
            setTitle("全屏")
            pushimagedata(false)
        }
        drawTextBox()
    }

    function setBlock() {
        obtn[0].style.display = 'block'
        obtn[1].style.display = 'block'
    }

    function setTitle(txt) {
        document.title = txt
    }

    function pimgOpacity() {
        if (imgOpa) {
            //console.log("imgOpa:", imgOpa)
            var opa = Number(getComputedStyle(imgOpa)['opacity']) + 0.1
            //console.log("opa:", opa)
            if (opa <= 1) {
                imgOpa.style.opacity = opa
            }
        }
    }

    function nimgOpacity() {
        if (imgOpa) {
            var opa = Number(getComputedStyle(imgOpa)['opacity']) - 0.1
            //console.log("opa:", opa)
            if (opa >= 0) {
                imgOpa.style.opacity = opa
            }
        }
    }

    function setGraffiti(filename) {
        var img = document.createElement("img")
        img.className = 'huaban'
        img.src = "treehole/" + filename + ".png"
        img.style.opacity = .1
        canvas3.insertBefore(img, myCanvas[0])
        imgOpa = img
    }

    function setComment(filename) {
        var img = document.createElement("img")
        img.className = 'huaban'
        img.src = "treehole/" + filename + ".png"
        img.style.opacity = .1
        canvas3.insertBefore(img, myCanvas[1])
        imgOpa = img
    }

    function setContent() {
        var s1 = pngname[0]
        if (s1 == 'g') {
            tid = pngname.replace('g', '')
            var img = document.createElement("img")
            img.className = 'huaban'
            var cSrc = pngname.replace("g", "c")
            img.src = "treehole/" + cSrc + ".png"
            img.style.opacity = .1
            canvas3.insertBefore(img, myCanvas[1])
            imgOpa = img
        }
        if (s1 == 'c') {
            tid = pngname.replace('c', '')
            var img = document.createElement("img")
            img.className = 'huaban'
            var gSrc = pngname.replace("c", "g")
            img.src = "treehole/" + gSrc + ".png"
            img.style.opacity = .1
            canvas3.insertBefore(img, myCanvas[0])
            imgOpa = img
        }
        pathToCanvas(folder + '/' + pngname + '.png')
        document.title = pngname
        var p1 = /^[gc]\d{13}$/
        if (p1.test(pngname)) {
            obtn[0].style.display = 'block'
            obtn[1].style.display = 'block'
        }
    }

    function initHB() {
        var width = window.innerWidth
        var height = window.innerHeight
        //d0.style.width = width + 'px'
        d0.style.height = height + 'px'
        //console.log("innerWidth:innerHeight=", window.innerWidth, window.innerHeight)
        if (pngname) {
            //9:16
            var disW = width / scaleW
            var disH = height / scaleH
            var disWH
            if (disW < disH) {
                disWH = disW
            } else {
                disWH = disH
            }
            //console.log("disWH1:disWH2=", disWH, Math.trunc(disWH))
            disWH = Math.trunc(disWH)
            width = disWH * scaleW
            height = disWH * scaleH
            //console.log("width:height:", width, height)
        }
        canvasWidth = width
        helpMsg.style.width = d1.style.width = canvasWidth + 'px'
        canvasHeight = height
        switch (text_Direction) {
            case 0:
                text.width = 0
                text.height = scaleH * 3
                text.x = 0
                text.y = 0
                break;
            case 1:
                text.width = scaleW * 5
                text.height = 0
                text.x = canvasWidth
                text.y = 0
                break;
        }
        /*
        var d3width = d3.getBoundingClientRect().width
        var dwidth = (window.innerWidth - width) / 2 - d3width
        
        d3.style.right = (dwidth > 0 ? dwidth : 0) + 'px'
        //console.log("dwidth:", dwidth)

        d3.style.display = "none"
        */
        if (width * dpr == myCanvas[2].width && height * dpr == myCanvas[2].height) {
            return
        }
        var base64 = myCanvas[0].toDataURL()
        canvas3.style.width = d0.style.width = width + 'px'
        canvas3.style.height = height + 'px'
        //console.log("d0.width:height=", width, height)
        for (var i = 0; i < myCanvas.length; i++) {
            myCanvas[i].width = width * dpr
            myCanvas[i].height = height * dpr
        }
        initCtx()
        return base64
    }

    function initCtx() {
        myCtx[0].lineWidth = 3
        myCtx[0].lineCap = 'round'
        myCtx[2].lineWidth = 5
        myCtx[2].lineCap = 'round'
        myCtx[2].strokeStyle = 'red'
        //console.log('initCtx:', dpr)
        for (var i = 0; i < myCtx.length; i++) {
            myCtx[i].scale(dpr, dpr)
        }
    }

    function pathToCanvas(path) {
        //console.log("pathToCanvas")
        var img = new Image()
        img.onload = () => {
            //console.log('load:', myCtx[0], myCanvas[0].width, myCanvas[0].height)
            for (var x in img) {
                if (x.includes('natural')) {
                    //console.log(x + ":" + img[x])
                }
            }
            var { naturalWidth, naturalHeight } = img
            //console.log(naturalWidth, naturalHeight, canvasWidth, canvasHeight)
            var x, y, width, height

            //按原比例缩放
            var scaleX = naturalWidth / canvasWidth
            var scaleY = naturalHeight / canvasHeight
            if (scaleX > 1 || scaleY > 1) {
                //图片大于画布需要等比列缩小
                var scale = scaleX > scaleY ? scaleX : scaleY
                width = naturalWidth / scale
                height = naturalHeight / scale
            } else {
                width = naturalWidth
                height = naturalHeight
            }
            width = Math.trunc(width)
            height = Math.trunc(height)
            x = (canvasWidth - width) / 2
            y = (canvasHeight - height) / 2

            //console.log("x:y", x, y, width, height, scaleX, scaleY)
            //myCtx[0].drawImage(img, x, y, width, height)
            //默认图片比例相同9/16铺满画布
            myCtx[0].drawImage(img, 0, 0, canvasWidth, canvasHeight)
            pushimagedata(false)
            uploadData = myCanvas[0].toDataURL()
            switch (text_Direction) {
                case 0:
                    var y = setTextY()
                    //console.log("y:", y)
                    text.y = y
                    break;
                case 1:
                    var x = setTextX()
                    text.x = x
                    break;
            }

            drawTextBox()
            // myCtx[0].fillRect(0, y, myCanvas[0].width, 1)
        }
        img.onerror = (err) => {
            //console.log('onerror:', err)
            if(huabuType=="6"){
                pathToCanvas("images/app_teamwork.png")
            }else{
                 pushimagedata(false)
            }
        }
        img.src = path
    }



    window.onresize = (evt) => {
        // console.log("resize:", evt)
        myRect = myCanvas[2].getBoundingClientRect()
        hbimagedata = []
        pathToCanvas(initHB())
        //移动端加载时调用，导致pushimagedata调用两次，撤销按钮变可用状态
    }


    function set_max_min(x, y) {
        //文字的最大值和最小值
        var change = false
        if (text.point.min.x === null) {
            text.point = { min: { x, y }, max: { x, y } }
        } else {
            var { max, min } = text.point
            if (min.x > x) {
                min.x = x
                change = true
            }
            if (min.y > y) {
                min.y = y
                change = true
            }
            if (max.x < x) {
                max.x = x
                change = true
            }
            if (max.y < y) {
                max.y = y
                change = true
            }
        }
        return change
    }

    function scale_width_height() {
        var { max, min } = text.point
        var widthX = max.x - min.x
        var heightY = max.y - min.y
        switch (text_Direction) {
            case 0:
                var scaleH = (text.height - text.fontsize) / (heightY || 0.001)
                //可能为0
                var scaleW = (text.height - text.fontsize) / (widthX || 0.001)
                //可能为0
                if (scaleH > 1) {
                    if (scaleH - scaleW > 0.5) {
                        text.scale = scaleW / 2
                    } else {
                        text.scale = 1
                    }
                } else {
                    text.scale = scaleH
                }
                text.width = widthX * text.scale + text.fontsize
                text.textheight = heightY * text.scale
                break;
            case 1:
                var scaleH = (text.width - text.fontsize) / (heightY || 0.001)
                var scaleW = (text.width - text.fontsize) / (widthX || 0.001)
                if (scaleW > 1) {
                    if (scaleW - scaleH > 0.5) {
                        text.scale = scaleH / 2
                    } else {
                        text.scale = 1
                    }
                } else {
                    text.scale = scaleW
                }
                text.height = heightY * text.scale + text.fontsize
                text.textheight = widthX * text.scale
                break;
        }

    }

    function setRemainderWidth() {
        //计算是否换行
        switch (text_Direction) {
            case 0:
                text.remainderwidth = text.x + getWidthMargin() - canvasWidth
                break;
            case 1:
                text.remainderwidth = text.y + getHeightMargin() - canvasHeight
                break;
        }
    }

    function clearCanvas(ctx, canvas) {
        ctx.clearRect(0, 0, canvas.width, canvas.height)
    }

    function drawTextRect(x, y) {
        myCtx[1].save()
        myCtx[1].lineWidth = 1
        switch (text_Direction) {
            case 0:
                myCtx[1].strokeRect(x, y, getWidthMargin(), getHeightMargin())
                myCtx[1].setLineDash([3, 3])
                myCtx[1].strokeRect(x + text.margin.left, y + text.margin.top, text.width, text.height)
                break;
            case 1:
                var w = getWidthMargin()
                var h = getHeightMargin()
                myCtx[1].strokeRect(x - w, y, w, h)
                myCtx[1].setLineDash([3, 3])
                myCtx[1].strokeRect(x + text.margin.left - w, y + text.margin.top, text.width, text.height)
                break;
        }
        myCtx[1].restore()
    }

    function getTempXY() {
        var x, y;
        switch (text_Direction) {
            case 0:
                y = text.y + getHeightMargin()
                if (y + getHeightMargin() > canvasHeight) {
                    y = 0
                }
                x = -(getWidthMargin() - text.remainderwidth)
                break;
            case 1:
                x = text.x - getWidthMargin()
                if (x - getWidthMargin() < 0) {
                    x = canvasWidth
                }
                y = -(getHeightMargin() - text.remainderwidth)
                break;
        }
        return { x, y }
    }

    function drawTextBox() {
        clearCanvas(myCtx[1], myCanvas[1])
        drawTextRect(text.x, text.y)
        if (text.remainderwidth > 0) {
            var t = getTempXY()
            drawTextRect(t.x, t.y)
        }
    }

    function drawLine(ctx, x1, y1, x2, y2) {
        /*
         *画线
         */
        ctx.beginPath()
        ctx.moveTo(x1, y1)
        ctx.lineTo(x2, y2)
        ctx.stroke()
    }

    function getWidthMargin() {
        return text.width + text.margin.left + text.margin.right
    }
    var tempText
    var vfxTimes
    var vfxTimer

    function vfxStart() {
        vfxMask.style.display = "block"
        tempText = {}
        vfxTimes = 6
        //tempText = deepClone(text)
        tempText.x = text.point.min.x
        tempText.y = text.point.min.y
        tempText.scale = 1
        tempText.stepx = (text.x - tempText.x) / vfxTimes
        tempText.stepy = (text.y - tempText.y) / vfxTimes
        tempText.stepScale = (text.scale - 1) / vfxTimes

        vfxTimer = setInterval(() => {
            drawVfx()
        }, 1)
        //console.log("tempText.stepScale:", tempText.stepScale)
    }

    function drawVfx() {
        clearCanvas(myCtx[2], myCanvas[2])
        vfxTimes--
        if (vfxTimes <= 0) {
            clearInterval(vfxTimer)
            vfxEnd()
            return
        }
        //console.log('vfxTimes:', vfxTimes)
        tempText.x += tempText.stepx
        tempText.y += tempText.stepy
        tempText.scale += tempText.stepScale
        //console.log("tempText.scale:", tempText.scale)
        switch (text_Direction) {
            case 0:
                drawpath2d(tempText.x, tempText.y, myCtx[2], tempText.scale)
                break;
            case 1:
                drawpath2d(tempText.x - getWidthMargin(), tempText.y, myCtx[2], tempText.scale)
                break;
        }
    }

    function vfxEnd() {
        clearInterval(vfxTimer)

        confirmText1()
        vfxMask.style.display = "none"
    }

    function confirmText() {

        //confirmText1()
        vfxStart()
    }

    function confirmText1() {

        if (text.path2d.length > 0) {
            switch (text_Direction) {
                case 0:
                    drawpath2d(text.x, text.y, myCtx[0], text.scale)
                    break;
                case 1:
                    drawpath2d(text.x - getWidthMargin(), text.y, myCtx[0], text.scale)
                    break;
            }
            if (text.remainderwidth > 0) {
                switch (text_Direction) {
                    case 0:
                        var y = text.y + getHeightMargin()
                        if (y + getHeightMargin() > canvasHeight) {
                            y = 0
                        }
                        var x = -(getWidthMargin() - text.remainderwidth)
                        drawpath2d(x, y, myCtx[0], text.scale)
                        text.y = y
                        text.x = text.remainderwidth
                        break;
                    case 1:
                        var t = getTempXY()
                        drawpath2d(t.x - getWidthMargin(), t.y, myCtx[0], text.scale)
                        text.x = t.x
                        text.y = text.remainderwidth
                        break;
                }

            } else {
                switch (text_Direction) {
                    case 0:
                        text.x += getWidthMargin()
                        break;
                    case 1:
                        text.y += getHeightMargin()
                        break;
                }
            }
            initText(false)
            drawTextBox()
        }
    }

    function initText(flag) {
        text.remainderwidth = 0
        text.point = { min: { x: null, y: null }, max: { x: null, y: null } }
        text.path2d = []
        text.textimagedata = []
        switch (text_Direction) {
            case 0:
                text.width = 0
                break;
            case 1:
                text.height = 0
                break;
        }
        clearCanvas(myCtx[2], myCanvas[2])
        clearCanvas(myCtx[1], myCanvas[1])
        d3.style.display = 'none'
    }

    function drawpath2d(x, y, ctx, scale) {
        //console.log("text:", txt)

        ctx.save()
        switch (text_Direction) {
            case 0:
                ctx.translate(x + text.fontsize / 2 + text.margin.left, y + text.margin.top + (text.height - text.textheight) / 2)
                break;
            case 1:
                ctx.translate(x + text.margin.left + (text.width - text.textheight) / 2, y + text.fontsize / 2)
                break;
        }
        ctx.rotate(text.rotate * Math.PI / 180)
        var path = text.path2d
        var { max, min } = text.point
        ctx.beginPath()
        for (var i = 0; i < path.length; i++) {
            ctx.moveTo((path[i][0].x - min.x) * scale, (path[i][0].y - min.y) * scale)
            for (var j = 1; j < path[i].length; j++) {
                ctx.lineTo((path[i][j].x - min.x) * scale, (path[i][j].y - min.y) * scale)
            }
        }
        ctx.stroke()
        ctx.restore()
        pushimagedata(false)
    }

    function erase(x, y, flag) {
        myCtx[1].clearRect(0, 0, myCanvas[1].width, myCanvas[1].height)
        myCtx[1].save()
        myCtx[1].fillStyle = 'orange'
        myCtx[1].globalAlpha = 0.5
        switch (eraser.type) {
            case 0:
                myCtx[1].fillRect(x - eraser.size / 2, y - eraser.size / 2, eraser.size, eraser.size)
                if (flag) {
                    myCtx[0].clearRect(x - eraser.size / 2, y - eraser.size / 2, eraser.size, eraser.size)
                }
                break;
            case 1:
                myCtx[1].beginPath()
                myCtx[1].arc(x, y, eraser.size / 2, 0, Math.PI * 2)
                myCtx[1].fill()
                if (flag) {
                    myCtx[0].save()
                    myCtx[0].beginPath()
                    myCtx[0].arc(x, y, eraser.size / 2, 0, Math.PI * 2)
                    myCtx[0].clip()
                    myCtx[0].clearRect(x - eraser.size / 2, y - eraser.size / 2, eraser.size, eraser.size)
                    myCtx[0].restore()
                }
                break;
        }
        myCtx[1].restore()
    }

    function start(event) {
        // myCtx[0].globalAlpha = 0.5
        event.preventDefault()
        event.stopPropagation()
        //console.log('start:', event)

        switch (event.type) {
            case 'touchstart':
                startX = event.changedTouches[0].clientX - myRect.x
                startY = event.changedTouches[0].clientY - myRect.y
                break;
            case 'mousedown':
                startX = event.offsetX
                startY = event.offsetY
                break;
        }
        isMouseDown = true
        switch (hbMode) {
            case 0:
                break;
            case 1:
                text.parr1 = []
                startTimeStamp = event.timeStamp
                isLongTap = false
                lTimer = setTimeout(() => {
                    isLongTap = true
                    //console.log("lTimer isLongTap is true")
                    // setTextPos(startX, startY,startX,startY)
                    showMsg("移动文字框", true)
                }, 700)
                break;
            case 2:
                erase(startX, startY, false)
                break;
        }
    }

    function move(event) {
        event.preventDefault()
        var endX, endY;
        switch (event.type) {
            case 'touchmove':
                endX = event.changedTouches[0].clientX - myRect.x
                endY = event.changedTouches[0].clientY - myRect.y
                break;
            case 'mousemove':
                endX = event.offsetX
                endY = event.offsetY
                break;
        }
        if (isMouseDown && (startX != endX || startY != endY)) {
            isMove = true
            switch (hbMode) {
                case 0:
                    myCtx[0].beginPath()
                    myCtx[0].moveTo(startX, startY)
                    myCtx[0].lineTo(endX, endY)
                    myCtx[0].stroke()
                    break;
                case 1:
                    /* if (isLongTap == undefined) {
                         var moveTimeStamp = event.timeStamp
                         if (moveTimeStamp - startTimeStamp > 3000) {
                             //文字模式长按移动文字框
                             isLongTap = true
                             
                         } else {
                             isLongTap = false
                         }
                     }*/
                    if (isLongTap) {
                        //console.log("longtap")
                        isMove = false
                        setTextPos(startX, startY, endX, endY)
                    } else {
                        clearTimeout(lTimer)
                        if (set_max_min(startX, startY)) {
                            scale_width_height()
                            setRemainderWidth()
                            drawTextBox()
                        }
                        drawLine(myCtx[2], startX, startY, endX, endY)
                        text.parr1.push({ x: startX, y: startY })
                    }
                    break;
                case 2:
                    erase(startX, startY, true)
                    break;
            }
            //console.log(event)
            startX = endX
            startY = endY
        }
    }

    function setTextPos(sX, sY, eX, eY) {
        var x = text.x + (eX - sX)
        var y = text.y + (eY - sY)
        var sx = 0,
            ey = canvasHeight;
        switch (text_Direction) {
            case 0:
                ey = canvasHeight - getHeightMargin()
                break;
            case 1:
                sx = getWidthMargin()
                break;
        }
        x = x < sx ? sx : x
        y = y < 0 ? 0 : y
        x = x > canvasWidth ? canvasWidth : x
        y = y > ey ? ey : y
        text.x = x
        text.y = y
        setRemainderWidth()
        drawTextBox()
    }

    function end(event) {
        event.preventDefault()
        //console.log("End:", event)
        var endX, endY;
        switch (event.type) {
            case 'touchend':
                endX = event.changedTouches[0].clientX - myRect.x
                endY = event.changedTouches[0].clientY - myRect.y
                break;
            case 'mouseup':
                endX = event.offsetX
                endY = event.offsetY
                break;
        }
        switch (hbMode) {
            case 0:
                if (isMove) {
                    pushimagedata(false)
                }
                break
            case 1:
                if (isLongTap) {
                    setTextPos(startX, startY, endX, endY)
                } else {
                    clearTimeout(lTimer)
                }
                if (isMove) {
                    text.parr1.push({ x: endX, y: endY })
                    set_max_min(endX, endY)
                    scale_width_height()
                    setRemainderWidth()
                    text.path2d.push(text.parr1)
                    text.textimagedata.push(myCtx[2].getImageData(0, 0, myCanvas[2].width, myCanvas[2].height))
                    d3.style.display = 'flex'
                } else {
                    if (!isLongTap) {
                        confirmText()
                    }
                }
                break
            case 2:
                //clearCanvas(myCtx[1], myCanvas[1])
                eraser.x = endX
                eraser.y = endY
                pushimagedata(true)
                break
        }
        isMouseDown = false
        isMove = false

    }

    function add_Save() {
        savePng()
    }

    function savePng() {
        console.log("phpquery:", phpquery)
        var fd = new FormData()
        myCanvas[0].toBlob(blob => {
            fd.append('image', blob, pngname + '.png')
            fetch(phpquery, { method: 'POST', body: fd }).then(response => {
                isUploading = false
                //console.log(response)
                if (response.ok) {
                    uploadData = hbimagedata[hbimagedata.length - 1]
                    showMsg("已上传", true);
                } else {
                    showMsg("上传失败", true);
                }
                return response.text()
            }).then(txt => {
                console.log("uploadPng:", txt)
                if (huabuType == "1" || huabuType == "2" || huabuType =="6") {
                    var key = pngname
                    if(huabuType=="6" || huabuType=="4"){
                        key = pngname.slice(1)
                    }
                  //  localStorage.setItem(huabuType + key, txt)
                  localStorage.setItem(pngname,txt);
                }
            }).catch(err => {
                isUploading = false
                showMsg("上传失败", true);
                //console.log(err)
            })
        }, 'image/png')
    }


    function uploadPng() {
        if (isUploading) {
            return
        }
        isUploading = true
        if (pngname) {
            if (isDataDiff()) {
                showMsg('上传中······', false)
                if (isBlank(myCanvas[0])) {
                    add_Save()
                } else {
                    showMsg("画布为空", true)
                    isUploading = false
                }
            } else {
                showMsg("没有更新", true)
                isUploading = false
            }
        } else {
            showMsg("正在使用离线版", true)
        }
    }
     function isDataDiff() {
        var length = hbimagedata.length
        if (length > 1) {
            var tdata = uploadData || hbimagedata[0]
            //console.log("test:test:", hbimagedata[length - 1] == tdata)
            return hbimagedata[length - 1] != tdata
        }
        return false
    }
     function isBlank(canvas) {
        var blank = document.createElement('canvas');
        blank.width = canvas.width;
        blank.height = canvas.height;
        return canvas.toDataURL() != blank.toDataURL();
    }
    </script>
</body>

</html>